﻿#region Licence
// <copyright file="Controls/EditableTextBlock.cs" company="Kopigi">
// Copyright © Kopigi 2014
// </copyright>
// ****************************************************************************
// <author>Marc PLESSIS</author>
// <date>10/10/2014</date>
// <project>Nentang.wpf</project>
// <web>http://nentang.codeplex.com</web>
// <license>
// The MIT License (MIT)
// 
// Copyright (c) 2013 Marc Plessis
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// 
// </license>
#endregion
#region using

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;

#endregion

namespace Controls
{
    /// <summary>
    /// TextBlock éditable au clic
    /// </summary>
    [TemplatePart(Type = typeof(Grid), Name = EditableTextBlock.GRID_NAME)]
    [TemplatePart(Type = typeof(TextBlock), Name = EditableTextBlock.TEXTBLOCK_DISPLAYTEXT_NAME)]
    [TemplatePart(Type = typeof(TextBox), Name = EditableTextBlock.TEXTBOX_EDITTEXT_NAME)]
    public class EditableTextBlock : Control
    {
        #region Constants

        private const string GRID_NAME = "PART_GridContainer";
        private const string TEXTBLOCK_DISPLAYTEXT_NAME = "PART_TbDisplayText";
        private const string TEXTBOX_EDITTEXT_NAME = "PART_TbEditText";

        #endregion

        #region Member Fields

        private Grid m_GridContainer;
        private TextBlock m_TextBlockDisplayText;
        private TextBox m_TextBoxEditText;
        public bool IsLostFocus;
        #endregion

        #region Dependency Properties

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(EditableTextBlock), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextChanged));

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //if(!string.IsNullOrEmpty((string)e.NewValue))
            //{
                var editable = ((EditableTextBlock)d);
                editable.Text = (string) e.NewValue;
                if (editable.m_TextBlockDisplayText != null)
                {
                    var bind = new Binding {Source = editable.Text};
                    BindingOperations.SetBinding(editable.m_TextBlockDisplayText, TextBlock.TextProperty, bind);
                    if (editable.IsLostFocus)
                    {
                        editable.OnApplyTemplate();
                    }
                }
            //}             
        }

        public Brush TextBlockForegroundColor
        {
            get { return (Brush)GetValue(TextBlockForegroundColorProperty); }
            set { SetValue(TextBlockForegroundColorProperty, value); }
        }

        public static readonly DependencyProperty TextBlockForegroundColorProperty = DependencyProperty.Register("TextBlockForegroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));



        public Brush TextBlockForegroundColorWatermark
        {
            get { return (Brush)GetValue(TextBlockForegroundColorWatermarkProperty); }
            set { SetValue(TextBlockForegroundColorWatermarkProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TextBlockForegroundColorWatermark.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextBlockForegroundColorWatermarkProperty =
            DependencyProperty.Register("TextBlockForegroundColorWatermark", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

        

        public Brush TextBlockBackgroundColor
        {
            get { return (Brush)GetValue(TextBlockBackgroundColorProperty); }
            set { SetValue(TextBlockBackgroundColorProperty, value); }
        }

        public static readonly DependencyProperty TextBlockBackgroundColorProperty = DependencyProperty.Register("TextBlockBackgroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

        public Brush TextBoxForegroundColor
        {
            get { return (Brush)GetValue(TextBoxForegroundColorProperty); }
            set { SetValue(TextBoxForegroundColorProperty, value); }
        }

        public static readonly DependencyProperty TextBoxForegroundColorProperty = DependencyProperty.Register("TextBoxForegroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

        public Brush TextBoxBackgroundColor
        {
            get { return (Brush)GetValue(TextBoxBackgroundColorProperty); }
            set { SetValue(TextBoxBackgroundColorProperty, value); }
        }

        public static readonly DependencyProperty TextBoxBackgroundColorProperty = DependencyProperty.Register("TextBoxBackgroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

        public string WatermarkText
        {
            get { return (string)GetValue(WatermarkTextProperty); }
            set { SetValue(WatermarkTextProperty, value); }
        }
        public static readonly DependencyProperty WatermarkTextProperty =
            DependencyProperty.Register("WatermarkText", typeof(string), typeof(EditableTextBlock), new UIPropertyMetadata(string.Empty));

        public bool MultiLine
        {
            get { return (bool)GetValue(MultiLineProperty); }
            set { SetValue(MultiLineProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MultiLine.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MultiLineProperty =
            DependencyProperty.Register("MultiLine", typeof(bool), typeof(EditableTextBlock), new UIPropertyMetadata(false));

        
        #endregion

        #region Constructor

        static EditableTextBlock()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(EditableTextBlock), new FrameworkPropertyMetadata(typeof(EditableTextBlock)));            
        }

        #endregion

        #region Overrides Methods

        public override void OnApplyTemplate()
        {
            IsLostFocus = true;
            base.OnApplyTemplate();

            this.m_GridContainer = this.Template.FindName(GRID_NAME, this) as Grid;

            if (this.m_GridContainer != null)
            {
                this.m_TextBlockDisplayText = ((Border)this.m_GridContainer.Children[0]).Child as TextBlock;
                this.m_TextBoxEditText = this.m_GridContainer.Children[1] as TextBox;
                var mTextBoxEditText = this.m_TextBoxEditText;
                if (mTextBoxEditText != null) mTextBoxEditText.LostFocus += this.OnTextBoxLostFocus;

                if(string.IsNullOrEmpty(Text))
                {
                    this.m_TextBlockDisplayText.Text = WatermarkText;
                    this.m_TextBlockDisplayText.Foreground = TextBlockForegroundColorWatermark;
                    this.m_TextBlockDisplayText.Visibility = Visibility.Hidden;
                    this.m_TextBoxEditText.Visibility = Visibility.Visible;
                }
                else
                {
                    this.m_TextBlockDisplayText.Foreground = TextBlockForegroundColor;
                    this.m_TextBlockDisplayText.Visibility = Visibility.Visible;
                    this.m_TextBoxEditText.Visibility = Visibility.Hidden;
                    IsLostFocus = true;
                }

                if(MultiLine)
                {
                    this.m_TextBoxEditText.AcceptsReturn = true;
                    this.m_TextBoxEditText.TextWrapping = TextWrapping.Wrap;
                    this.m_TextBoxEditText.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                    this.m_TextBlockDisplayText.TextWrapping = TextWrapping.Wrap;
                }
            }
        }

        protected override void OnGotFocus (RoutedEventArgs e)
        {
            IsLostFocus = false;
            if(!IsLostFocus)
            {
                base.OnGotFocus(e);
                this.m_TextBlockDisplayText.Visibility = Visibility.Hidden;
                this.m_TextBoxEditText.Visibility = Visibility.Visible;
                this.m_TextBoxEditText.Focus();
            }
            else
            {
                IsLostFocus = true;
            }
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            this.m_TextBlockDisplayText.Visibility = Visibility.Hidden;
            this.m_TextBoxEditText.Visibility = Visibility.Visible;
            this.m_TextBoxEditText.Focus();
            this.m_TextBoxEditText.SelectAll();
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            if((e.Key == Key.Enter || e.Key == Key.Return) && Keyboard.Modifiers == ModifierKeys.None)
            {
                OnTextBoxLostFocus(this,new RoutedEventArgs());
            }
            else
            {
                if(MultiLine && (e.Key == Key.Enter && Keyboard.Modifiers == ModifierKeys.Control))
                {
                    this.m_TextBoxEditText.Text += Environment.NewLine;
                    this.m_TextBoxEditText.SelectionStart = this.m_TextBoxEditText.Text.Length;
                }
            }
        }

        #endregion

        #region Event Handlers

        private void OnTextBoxLostFocus(object sender, RoutedEventArgs e)
        {
            this.m_TextBlockDisplayText.Visibility = Visibility.Visible;
            this.m_TextBoxEditText.Visibility = Visibility.Hidden;
            this.m_TextBlockDisplayText.Foreground = string.IsNullOrEmpty(Text) ? TextBlockForegroundColorWatermark : TextBlockForegroundColor;
            
            IsLostFocus = true;
            SetFocusOff();
        }

        private void SetFocusOff()
        {
            var parent = (FrameworkElement)this.m_TextBoxEditText.Parent;
            while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
            {
                parent = (FrameworkElement)parent.Parent;
            }

            var scope = FocusManager.GetFocusScope(this.m_TextBoxEditText);
            FocusManager.SetFocusedElement(scope, parent as IInputElement);
        }
        #endregion
    }
}
